package database.team.phase1;


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;


import database.team.phase2.BagDifference;
import database.team.phase2.RunPhase2;
import database.team.phase2.SortedJoinBlocks;
import database.team.phase2.checkFolder;

/**
 *  External sorting 
 *  Limitations: restricted main memory of 5MB using arguments "-Xms5m -Xmx5m"
 *  Input:      file with unsorted integers 
 *  Output: file with sorted integers
 */
public class RunPhase3 {
        static int no_inputBuffers = 0;
        static int counter = 0;
        static int numOfTuplesEmp = 0;
        static int numOfTuplesDept = 0;
        static int counterIO = 0;
        public static int phase2_counterIO=0;
        static String line;
        
        public static void main(String[] args){
        	 try{
                  	BufferedReader fileSize = new BufferedReader(new InputStreamReader(new DataInputStream(new FileInputStream("Emp1.txt"))));
                    while((line = fileSize.readLine())  != null) numOfTuplesEmp++;
                    long startTime = System.currentTimeMillis();
                    //list to store the input temporary files location
                    List<File> tempFileList;
                    checkFolder cleanFolder = new checkFolder();
                    cleanFolder.cleanFolder("TableEmp1");
                    cleanFolder.cleanFolder("TableEmp2");
                    System.out.println("Phase I started..");
                    tempFileList = processPhaseI(new File("Emp1.txt"), "TableEmp1");
                                
                    System.out.println(tempFileList);
                    System.out.println("Created Temp Files: " + tempFileList.size());
                    no_inputBuffers = tempFileList.size();
                    
                    counter = 0;
                        
                    fileSize = new BufferedReader(new InputStreamReader(new DataInputStream(new FileInputStream("Emp2.txt"))));
                    while((line = fileSize.readLine())  != null) numOfTuplesDept++;
                    
                    tempFileList = processPhaseI(new File("Emp2.txt"), "TableEmp2");
                    
                    System.out.println(tempFileList);
                    System.out.println("Created Temp Files: " + tempFileList.size());
                    no_inputBuffers = tempFileList.size();
                    
                    System.out.println("Phase I finished.");
                    long endTime = System.currentTimeMillis();
                    System.out.println("Phase I time is: " + (endTime - startTime) + " msec");
                    System.out.println("DiskI/O for phase1:"+counterIO);
                    long startTimePhase2 = System.currentTimeMillis();
                    System.out.println("Phase II started..for Emp");
                               
               	    RunPhase2 runphase2 = new RunPhase2();
                    runphase2.processPhase2(numOfTuplesEmp, "TableEmp1");
                    System.out.println("Phase II started..for Dept");
                    runphase2.processPhase2(numOfTuplesDept, "TableEmp2");
                    Long endTimePhase2 = System.currentTimeMillis();
                    System.out.println("Phase II time is: " + (endTimePhase2 - startTimePhase2) + " msec");
                    System.out.println("Phase II finished.");
                    System.out.println("BagDifference between tables Employee1 and Employee2");
                    long startTimeBag = System.currentTimeMillis();
                    new BagDifference();
                    //int diskIOJoin = sortedjoin.SortedJoin();
                    long endTimeBag = System.currentTimeMillis();
               	 	float totalTimeBag = (endTimeBag - startTimeBag);
               	    //since diskIO for phase2 is same as phase1
                    System.out.println("DiskI/O for phase2: "+phase2_counterIO);
                    float totalTime = (endTime - startTime) + (endTimePhase2 - startTimePhase2);
                    System.out.println("Total time for 2pmms for Tables Employee1 and Employee2: "+totalTime+""); 
                    System.out.println("Total DiskI/O for 2pmms: "+(counterIO+phase2_counterIO));
                    System.out.println("Total time to perform the Bag Difference between the tables Empl1 and Empl2: "+totalTimeBag+" ms"); 
               	    //System.out.println("Total Disk I/O's to join the tables: "+diskIOJoin);
               	    System.out.println("The result is shown in the file BagDifference.txt");
                    //}
                } catch(IOException e1){
                	e1.printStackTrace();
                }
        }

        /**
         * Method ProcessPhaseI this method performs the following operations
         * 1. reads the data from the main file
         * 2. calculates the memory available to get and sort
         * 3. performs sort on the numbers
         * 4. writes to a temporary file 
         * @param  Original file with unsorted numbers
         * @return List of files with pointers
         * @throws IOException throws input and output exception
         */
        public static List<File> processPhaseI(File file, String subdir) throws IOException {
        		//stores the information regarding file
                List<File> files = new ArrayList<File>();
                BufferedReader fbr = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
                long sizeoffile = file.length();
                long blocksize = sizeoffile / 1024 + (sizeoffile % 1024 == 0 ? 0 : 1);
                long freemem = Runtime.getRuntime().freeMemory();
                if (blocksize < freemem / 2) {
                        blocksize = freemem/4;
                }
                try {
                        //temp list to store the data of integers and store it
                        List<String> tmplist = new ArrayList<String>();
                        String line = "";
                        try {
                                while (line != null) {
                                        long currentblocksize = 0;      //in bytes
                                        while ((currentblocksize < blocksize) && ((line = fbr.readLine()) != null)) { 
                                                tmplist.add(line);
                                                currentblocksize += line.length() * 2;
                                        }
                                        counterIO++;
                                        //creates and stores the data into temp file
                                        files.add(sortAndStoreToTemporaryFile(tmplist, subdir));
                                        tmplist.clear();
                                }
                        } catch (EOFException oef) {
                                if (tmplist.size() > 0) {
                                        files.add(sortAndStoreToTemporaryFile(tmplist, subdir));
                                        tmplist.clear();
                                }
                        }
                } finally {
                        fbr.close();
                }
                return files;
        }

        /**
         * Method sortAndStoreToTemporaryFile creates a new temporary file and stores the sorted chunk of integers
         * @param  tmplist list of unsorted integers
         * @return the file information
         * @throws IOException throws input/output exception
         */
        public static File sortAndStoreToTemporaryFile(List<String> tmplist, String subdir) throws IOException {
        		counterIO++;
                QuickSort.getInstance().quickSort(tmplist, 0, tmplist.size()-1);
                
                File newtmpfile = new File(subdir+File.separator+"intermediateFile" + ++counter + ".tmp");
                newtmpfile.getParentFile().mkdirs();
                newtmpfile.createNewFile();
                
                BufferedWriter fbw = new BufferedWriter(new FileWriter(newtmpfile));
                
                try {
                        for (String r : tmplist) {
                                fbw.write("" + r);
                                fbw.newLine();
                        }
                } finally {
                        fbw.close();
                }
                return newtmpfile;
        }
}